#include "stdlib.hpp"

#include <purewell/barrier.hpp>

namespace purewell
{

PWBarrier::PWBarrier(size_t count, const PWBarrierAttribute* pattr)
{
#if defined(HAVE_POSIX_BARRIER)
	pthread_barrier_t* pthis(new pthread_barrier_t);
	if ( NULL == pthis )
	{
		return;
	}

	if ( 0 != pthread_barrier_init(pthis,
		(pattr?(pthread_barrierattr_t*)(pattr->getData()):NULL), count) )
	{
		delete pthis;
		return;
	}

	m_pData = pthis;

#else
	__PWERRNO_NOIMPL();
#endif
}

PWBarrier::~PWBarrier()
{
#if defined(HAVE_POSIX_BARRIER)
	if ( m_pData )
	{
		pthread_barrier_t* pthis((pthread_barrier_t*)m_pData);
		pthread_barrier_destroy(pthis);
		delete pthis;
		m_pData = NULL;
	}
#else
	__PWERRNO_NOIMPL();
#endif
}

void
PWBarrier::release(PWBarrier* obj)
{
	delete obj;
}

PWBarrier*
PWBarrier::create(size_t count, const PWBarrierAttribute* pattr)
{
#if defined(HAVE_POSIX_BARRIER)
	PWBarrier* ret(new PWBarrier(count, pattr));
	if ( NULL == ret ) return NULL;

	if ( NULL == ret->m_pData )
	{
		delete ret;
		return NULL;
	}

	return ret;
#else
	__PWERRNO_NOIMPL();
	return NULL;
#endif
}

bool
PWBarrier::wait(void)
{
#if defined(HAVE_POSIX_BARRIER)
	pthread_barrier_t* pthis((pthread_barrier_t*)m_pData);
	const int res(pthread_barrier_wait(pthis));
	return ( 0 == res || PTHREAD_BARRIER_SERIAL_THREAD == res );
#else
	__PWERRNO_NOIMPL();
	return false;
#endif
}

PWBarrierAttribute::PWBarrierAttribute()
{
#if defined(HAVE_POSIX_BARRIER)
	pthread_barrierattr_t* pthis(new pthread_barrierattr_t);
	if ( NULL == pthis ) return;

	if ( 0 != pthread_barrierattr_init(pthis) )
	{
		delete pthis;
		return;
	}

	m_pData = pthis;
#else
	__PWERRNO_NOIMPL();
#endif
}


PWBarrierAttribute::~PWBarrierAttribute()
{
#if defined(HAVE_POSIX_BARRIER)
	if ( m_pData )
	{
		pthread_barrierattr_t* pthis((pthread_barrierattr_t*)m_pData);
		delete pthis;
		m_pData = NULL;
	}
#else
	__PWERRNO_NOIMPL();
#endif
}

PWBarrierAttribute*
PWBarrierAttribute::create(void)
{
#if defined(HAVE_POSIX_BARRIER)
	PWBarrierAttribute* res(new PWBarrierAttribute);
	if ( NULL == res ) return NULL;
	if ( NULL == res->m_pData )
	{
		delete res;
		return NULL;
	}

	return res;
#else
	__PWERRNO_NOIMPL();
	return NULL;
#endif
}

void
PWBarrierAttribute::release(PWBarrierAttribute* obj)
{
	delete obj;
}

};

